﻿from System import *
from System.Windows import * 
from System.Windows.Controls import *
from System.Windows.Input import *
from System.Windows.Media import *
#from System.Windows.Media.Imaging import BitmapImage # for bitmap
from System.Collections.Generic import List
from System.Windows.Threading import DispatcherTimer
from System.Windows.Browser import HtmlPage
from System.IO import StringReader
from System.Net import * # for WebClient
from System.Windows.Resources import * # for WebClient

#from System.Security.Cryptography import *
#from System.Text import *
import clr
clr.AddReference("System.Xml")
from System.Xml import XmlReader, XmlNodeType
import System

_isScrubberLocked = False
_positionTimer = None
_loop = False
_src = String.Empty
_volume = 0.5
_width = 400
_height = 45
_autoPlay = True
_muted = False
_controls = False
_autoBuffer = False
_ended = False

class SourceElement(object):
	src = ""
	type = ""
	title = ""
	artist = ""

class MediaInfo(object):
    def __init__(self, xml):
		self._xml = xml
		self.Sources = List[String]()
		self.Video = False
		self.Loop = True
		self.Autoplay = True
		self.Volume = .5
		self.Width = 300
		self.Height = 150
		self.Poster = None
		self.Controls = True
		self.Autobuffer = True
		self.Muted = False

		reader = XmlReader.Create(StringReader(self._xml))
		# can handle elements in any order
		while (reader.Read()):
			if reader.Name == "video":
				self.Video = reader.ReadElementContentAsBoolean()
			elif reader.Name == "width":
				self.Width = reader.ReadElementContentAsDouble()
			elif reader.Name == "height":
				self.Height = reader.ReadElementContentAsDouble()
			elif reader.Name == "autoplay":
				self.Autoplay = reader.ReadElementContentAsString()
			elif reader.Name == "volume":
				self.Volume = reader.ReadElementContentAsDouble()
			elif reader.Name == "poster":
				self.Poster = reader.ReadElementContentAsString()
			elif reader.Name == "loop":
				self.Loop = reader.ReadElementContentAsBoolean()
			elif reader.Name == "controls":
				self.Controls = reader.ReadElementContentAsBoolean()
			elif reader.Name == "autobuffer":
				self.Autobuffer = reader.ReadElementContentAsBoolean()
			elif reader.Name == "muted":
				self.Muted = reader.ReadElementContentAsBoolean()
			elif reader.Name == "sources":
				item = None
				while (reader.Read()):
					if reader.Name == "source":
						item = reader.ReadElementContentAsString()
						self.Sources.Add(item)
                
class PlayList(object):
    def __init__(self, xml):
        self._xml = xml
        self.Sources = List[SourceElement]()
        
        reader = XmlReader.Create(StringReader(self._xml))
        
        item = None
        while (reader.Read()):
            if reader.NodeType == XmlNodeType.Element and reader.Name == "location":
                item = reader.ReadElementContentAsString()
                source = SourceElement()
                source.src = item
                self.Sources.Add(source)                        
    
class SelectableSourceElementList (List[SourceElement]):
    #_clrclassattribs = [ScriptableTypeAttribute]

    LastItem = True
    def __init__(self):
        self._SelectedIndex = 0
        
    def Next(self):
        self._SelectedIndex = self._SelectedIndex + 1
        
        if self._SelectedIndex + 1 > self.Count:
            self._SelectedIndex = 0
            LastItem = True
        else:
            LastItem = False
            
    def Previous(self):
        self._SelectedIndex = self._SelectedIndex - 1
        if self._SelectedIndex < 0:
            self._SelectedIndex = self.Count - 1
            
    def SetSelectedItem(self, value):
        pass
    def GetSelectedItem(self):
        if self[self._SelectedIndex] != None:
            return self[self._SelectedIndex]
        else:
            return None
    SelectedItem = property(GetSelectedItem, SetSelectedItem)
    
    def SetSelectedIndex(self, value):
        self._SelectedIndex = value
    def GetSelectedIndex(self):
        return self._SelectedIndex
    SelectedIndex = property(GetSelectedIndex, SetSelectedIndex) 

def ConvertHexToColor(hexColor):
    c = Color()
    c = Color.FromArgb(
        Convert.ToUInt32(hexColor.Substring(1, 2), 16), 
        Convert.ToUInt32(hexColor.Substring(3, 2), 16), 
        Convert.ToUInt32(hexColor.Substring(5, 2), 16), 
        Convert.ToUInt32(hexColor.Substring(7, 2), 16))				
    return c
    
def DomGetFullPathToDir():
    content = ""
    try:
        path = HtmlPage.Document.DocumentUri.ToString()
        segments = path.Split('/')
        content = path.Replace(segments[segments.Length - 1], "")
    except:
        pass
    return content
            
def EnsureAbsoluteFilePath(initialPath):
    if String.IsNullOrEmpty(initialPath):
        return String.Empty

    if initialPath.ToLower().Contains("http://"):
        return initialPath
    else:
        s = DomGetFullPathToDir()
        return s + initialPath
        
def Opened(s, e):
    me.Player.Play()
    
def _Play():
    if me.Player.CurrentState != MediaElementState.Playing:
        
        if MediaCollection.Count > 0:
            if me.Player.Position.TotalSeconds == 0: # only queue up next video if the current one is finished playing
                me.Player.Source = Uri(MediaCollection.SelectedItem.src, UriKind.Absolute)
                me.Caption.Text = ""
                
        if me.Player.AutoPlay == False:
            me.Player.MediaOpened += Opened
        else:
            if  me.Player.CurrentState != MediaElementState.Playing: # don't try to play if it's already playing
                me.Player.Play()
        
def _Stop():
    pass
    
def Next():
    me.Player.Pause()
    me.Player.Position = TimeSpan(0, 0, 0)
    if MediaCollection.Count > 1:
        MediaCollection.Next()
    _Play()
    
def Previous():
    me.Player.Pause()
    me.Player.Position = TimeSpan(0, 0, 0)
    if MediaCollection.Count > 1:
        MediaCollection.Previous()
    _Play()

# define event handlers
def positionTimer_Tick(s,e):
    if me.Player.Position.TotalSeconds > 0 and not _isScrubberLocked:
        me.Scrubber.Value = Convert.ToDouble(me.Player.Position.Ticks) / Convert.ToDouble(me.Player.NaturalDuration.TimeSpan.Ticks)
        me.MsgCurrentTime.Text = String.Format("{0:00}:{1:00}:{2:00}", 
            me.Player.Position.Hours, me.Player.Position.Minutes, me.Player.Position.Seconds)

def Player_MediaOpened(s, e):
    me.Scrubber.Value = 0
    me.MsgTotalTime.Text = String.Format("{0:00}:{1:00}:{2:00}", 
        me.Player.NaturalDuration.TimeSpan.Hours, 
        me.Player.NaturalDuration.TimeSpan.Minutes, 
        me.Player.NaturalDuration.TimeSpan.Seconds)
    
def Player_CurrentStateChanged(s, e):
    if me.Player.CurrentState == MediaElementState.Playing:
        me.ShowPauseButton.Begin()
        _positionTimer.Start()
        
    elif me.Player.CurrentState == MediaElementState.Paused:
        me.ShowPlayButton.Begin()
        _positionTimer.Stop()
        
    if me.Player.CurrentState == MediaElementState.Stopped:
        me.ShowPlayButton.Begin()
        _positionTimer.Stop()
        me.Scrubber.Value = 0
        
def Player_DownloadProgressChanged(s, e):
    me.DownloadProgressTrack.RenderTransform.ScaleX = me.Player.DownloadProgress
    
def Scrubber_MouseLeave(s, e):
    global _isScrubberLocked
    _isScrubberLocked = False

def Scrubber_MouseMove(s, e):
    global _isScrubberLocked
    _isScrubberLocked = True

def Scrubber_MouseLeftButtonUp(s, e):
    global _isScrubberLocked
    me.Player.Position = TimeSpan.FromSeconds(me.Scrubber.Value * me.Player.NaturalDuration.TimeSpan.TotalSeconds)
    _isScrubberLocked = False
    
def BtnPlayPause_MouseLeftButtonUp(s, e):
    if me.Player.CurrentState == MediaElementState.Playing:
        me.Player.Pause()
    elif me.Player.CurrentState == MediaElementState.Paused:
        _Play()
    elif me.Player.CurrentState == MediaElementState.Stopped:
        _Play()
        
def BtnPlayPause_MouseLeave(s, e):
    me.PlayPauseSymbol_MouseLeave.Begin()

def BtnPlayPause_MouseEnter(s, e):
    me.PlayPauseSymbol_MouseEnter.Begin()
    
def VolumeSlider_ValueChanged(s, e):
    me.Player.Volume = me.VolumeSlider.Value
    
def ShowControlPanel_Completed(s, e):
    me.ControlPanelTimer.Begin()

def ShowVolumeSlider_Completed(s, e):
    me.VolumeSliderTimer.Begin()

def VolumeSliderCanvas_MouseMove(s, e):
    me.VolumeSliderTimer.Begin()

def VolumeSliderTimer_Completed(s, e):
    me.HideVolumeSlider.Begin()
    
def ControlPanelTimer_Completed(s, e):
    me.HideControlPanel.Begin()    

def BtnVolume_MouseLeftButtonUp(s, e):
    me.ShowVolumeSlider.Begin()
    
def Player_MouseMove(s, e):
    if settings.Video:
        me.ShowControlPanel.Begin()  
    
def Player_MouseLeave(s, e):
    me.ControlPanelTimer.Begin()      
    
def BtnVolume_MouseEnter(s, e):
    me.VolumeSymbol_MouseEnter.Begin()    
    
def BtnVolume_MouseLeave(s, e):   
    me.VolumeSymbol_MouseLeave.Begin()
    
def NextSymbol_MouseEnter(s, e):
    me.NextSymbol_MouseEnter.Begin()
    
def NextSymbol_MouseLeave(s, e):   
    me.NextSymbol_MouseLeave.Begin()
    
def PreviousSymbol_MouseEnter(s, e):
    me.PreviousSymbol_MouseEnter.Begin()
    
def PreviousSymbol_MouseLeave(s, e):   
    me.PreviousSymbol_MouseLeave.Begin() 
    
def FullSymbol_MouseEnter(s, e):
    me.FullSymbol_MouseEnter.Begin()
    
def FullSymbol_MouseLeave(s, e):   
    me.FullSymbol_MouseLeave.Begin()          
    
def Player_MarkerReached(s, e):
    me.Caption.Text = e.Marker.Text
    
def FullSymbol_MouseLeftButtonDown(s, e):
    Application.Current.Host.Content.IsFullScreen = not Application.Current.Host.Content.IsFullScreen
    me.Width = Application.Current.Host.Content.ActualWidth
    me.Height = Application.Current.Host.Content.ActualHeight
    
def BrowserHost_Resize(s, e):
    me.Width = Application.Current.Host.Content.ActualWidth
    me.Height = Application.Current.Host.Content.ActualHeight

def Player_MediaEnded(s, e):
    me.Player.Position = TimeSpan(0, 0, 0)
    
    if MediaCollection.Count > 0: # is there a playlist?
        if _loop: # just keep looping
            MediaCollection.Next()
            _Play()
        else:
            MediaCollection.Next()
            if MediaCollection.SelectedIndex > 0: # check to see if we've finished the playlist
                _Play()
            else:
                _Stop()
    elif _loop:
        _Play()
    else:
        _Stop()
        
def Player_MediaFailed(s, e):
    me.Caption.Text = "Issue loading file: " + MediaCollection.SelectedItem.src
    #HtmlPage.Window.Invoke("error", s, e);        
    
def GoNext(s, e):
    Next()

def GoPrevious(s, e):
    Previous()   

# register for player and UI events
me.Player.MediaOpened += Player_MediaOpened
me.Player.CurrentStateChanged += Player_CurrentStateChanged
me.Player.DownloadProgressChanged += Player_DownloadProgressChanged
me.Player.MarkerReached += Player_MarkerReached
me.Player.MediaEnded += Player_MediaEnded
me.Player.MediaFailed += Player_MediaFailed
me.Player.MouseMove += Player_MouseMove

me.Scrubber.MouseLeftButtonUp += Scrubber_MouseLeftButtonUp
me.Scrubber.MouseMove += Scrubber_MouseMove
me.Scrubber.MouseLeave += Scrubber_MouseLeave

me.BtnPlayPause.MouseEnter += BtnPlayPause_MouseEnter
me.BtnPlayPause.MouseLeave += BtnPlayPause_MouseLeave
me.BtnPlayPause.MouseLeftButtonUp += BtnPlayPause_MouseLeftButtonUp

me.BtnVolume.MouseEnter +=  BtnVolume_MouseEnter
me.BtnVolume.MouseLeave +=  BtnVolume_MouseLeave
me.BtnVolume.MouseLeftButtonUp += BtnVolume_MouseLeftButtonUp

me.VolumeSlider.ValueChanged += VolumeSlider_ValueChanged
me.ShowVolumeSlider.Completed += ShowVolumeSlider_Completed
me.VolumeSliderTimer.Completed += VolumeSliderTimer_Completed
me.VolumeSliderCanvas.MouseMove += VolumeSliderCanvas_MouseMove

me.ControlPanel.MouseMove += Player_MouseMove
me.ShowControlPanel.Completed += ShowControlPanel_Completed
me.Player.MouseLeave += Player_MouseLeave
me.ControlPanelTimer.Completed += ControlPanelTimer_Completed

me.NextSymbol.MouseEnter +=  NextSymbol_MouseEnter
me.NextSymbol.MouseLeave +=  NextSymbol_MouseLeave
me.NextSymbol.MouseLeftButtonDown += GoNext

me.PreviousSymbol.MouseLeftButtonDown += GoPrevious
me.PreviousSymbol.MouseEnter +=  PreviousSymbol_MouseEnter
me.PreviousSymbol.MouseLeave +=  PreviousSymbol_MouseLeave

# set to True if you want to override the element colors defined in the XAML
if False:
	# must be ARGB format
	ButtonOffHexValue = "#ffbbbbbb" # color of buttons when mouse is not over
	ButtonOverHexValue = "#ffeeeeee" # color of buttons when mouse is hovering
	PanelBackgroundHexValue = "#66ffffff" # The control panel background color
	TextColorHexValue = "#ff808080" # the color of the timecode and caption
	MediaBackDropHexValue = "#ff000000" # the color of the overall media player background

	# set colors
	fillColor = SolidColorBrush(ConvertHexToColor(ButtonOffHexValue))
	me.PlaySymbol.Fill = fillColor 
	me.PauseSymbol.Fill = fillColor
	me.SpeakerShape.Fill = fillColor
	me.VolumeShape1.Stroke = fillColor
	me.VolumeShape2.Stroke = fillColor
	me.NextA.Fill = fillColor
	me.NextB.Fill = fillColor
	me.PreviousA.Fill = fillColor
	me.PreviousB.Fill = fillColor

	background = SolidColorBrush(ConvertHexToColor(PanelBackgroundHexValue))
	me.VolumeSliderBackground.Fill = background
	me.ControlPanelBackground.Fill = background
	foreground = SolidColorBrush(ConvertHexToColor(TextColorHexValue))
	me.MsgCurrentTime.Foreground = foreground
	me.Caption.Foreground = foreground
	me.TimeDivider.Foreground = foreground
	me.MsgTotalTime.Foreground = foreground
	backdrop = SolidColorBrush(ConvertHexToColor(MediaBackDropHexValue))
	me.MediaBackground.Fill = backdrop
	me.LayoutRoot.Background = backdrop

	# set the storyboard To values for mouseleave events
	buttonOffHexValue = ConvertHexToColor(ButtonOffHexValue) 
	me.Stop_MouseLeaveValue.To = buttonOffHexValue
	me.Play_MouseLeaveValue.To = buttonOffHexValue
	me.Pause_MouseLeaveValue.To = buttonOffHexValue
	me.Volume_MouseLeaveValue.To = buttonOffHexValue
	me.Volume1_MouseLeaveValue.To = buttonOffHexValue
	me.Volume2_MouseLeaveValue.To = buttonOffHexValue
	me.NextA_MouseLeaveValue.To = buttonOffHexValue
	me.NextB_MouseLeaveValue.To = buttonOffHexValue
	me.PreviousA_MouseLeaveValue.To = buttonOffHexValue
	me.PreviousB_MouseLeaveValue.To = buttonOffHexValue

	# set the storyboard To values for mouseenter events
	buttonOverHexValue = ConvertHexToColor(ButtonOverHexValue)
	me.Stop_MouseEnterValue.To = buttonOverHexValue
	me.Play_MouseEnterValue.To = buttonOverHexValue
	me.Pause_MouseEnterValue.To = buttonOverHexValue
	me.Volume_MouseEnterValue.To = buttonOverHexValue
	me.Volume1_MouseEnterValue.To = buttonOverHexValue
	me.Volume2_MouseEnterValue.To = buttonOverHexValue
	me.NextA_MouseEnterValue.To = buttonOverHexValue
	me.NextB_MouseEnterValue.To = buttonOverHexValue
	me.PreviousA_MouseEnterValue.To = buttonOverHexValue
	me.PreviousB_MouseEnterValue.To = buttonOverHexValue

# start timer for UI updates
_positionTimer = DispatcherTimer()
_positionTimer.Interval = TimeSpan(0, 0, 0, 0, 100)
_positionTimer.Tick += positionTimer_Tick
_positionTimer.Start()

#get XML from page DOM
#name = Application.Current.Host.InitParams["xamlid"].Split("-")[0]
#xmlSettings = HtmlPage.Document.GetElementById(name + "-settings").text
xmlSettings = HtmlPage.Document.GetElementById("audio1-settings").text
settings = MediaInfo(xmlSettings)

# assign values declared in markup
_loop = settings.Loop
me.Width = settings.Width
me.Height = settings.Height

ap = settings.Autoplay
me.Player.AutoPlay = ap
    
me.Player.Volume = settings.Volume
me.Player.IsMuted = settings.Muted
if not settings.Controls:
    me.ControlPanel.Visibility = Visibility.Collapsed
    
if not settings.Video:
    me.Player.Visibility = Visibility.Collapsed
    me.LayoutRoot.RowDefinitions[0].Height = GridLength(0)
    me.MediaBackground.Visibility = Visibility.Collapsed 
    me.ControlPanel.Opacity = 1
    
#MediaCollection = SelectableSourceElementList()
#for i in range( 0, settings.Sources.Count):
#    s = SourceElement()
#    s.src = EnsureAbsoluteFilePath(settings.Sources[i])
#    MediaCollection.Add(s)
#me.Player.Source = Uri(MediaCollection.SelectedItem.src, UriKind.RelativeOrAbsolute)

# MD5 function is broken
#def getMd5Hash(input):
#    md5Hasher = System.Security.Cryptography.MD5.Create()
#    data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input))
#    sBuilder = StringBuilder()
#    for i in range( 0, data.Length):
#        sBuilder.Append(data[i].ToString("x2"))
#    return sBuilder.ToString()
    
#window.Alert(HtmlPage.Window.Invoke("GetMD5", "hello how are you?"))    

api_key = "79354f7ba19d5bc4474ff2d23fe7fa1a"
secret = "30875c37c3565a4c4244d2a2105228ab"
response = None
base_url = "http://ws.audioscrobbler.com/2.0/"
session_key = "ad873db0d0347d60644f574bfaeb91c2"

def webclient_UploadStringCompleted(s, e):
	if e.Error == None:
		pass
		#window.Alert( e.Result)
	else:
		pass
		#window.Alert(e.Error.ToString());
		
MediaCollection = SelectableSourceElementList()		
		
def webclient_DownloadStringCompleted(s, e):
	global MediaCollection
	if e.Error == None:
		#window.Alert(e.Result)
		playlist = PlayList(e.Result)
		for i in range( 0, playlist.Sources.Count):
		    s = SourceElement()
		    s.src = EnsureAbsoluteFilePath(playlist.Sources[i].src)
		    MediaCollection.Add(s)
		me.Player.Source = Uri(MediaCollection.SelectedItem.src, UriKind.RelativeOrAbsolute)
		
	else:
		window.Alert(e.Error.ToString());		

# This "tunes" in to a station
def TuneIn(artist):
    method = "radio.tune"
    postData = "api_key=" + api_key + "&" + "flashresponse=true&" + "method=" + method + "&" + "sk=" + session_key + "&" + "station=/listen/artist/" + artist + "&" + "api_sig="
    presig = "api_key" + api_key + "flashresponsetrue" + "method" + method + "sk" + session_key + "station/listen/artist/" + artist + secret
    api_sig = HtmlPage.Window.Invoke("GetMD5", presig)
    postData +=  api_sig
    webclient = WebClient()
    webclient.UploadStringCompleted += webclient_UploadStringCompleted
    #webclient.Headers.Add("Content-Type: application/x-www-form-urlencoded")
    #window.Alert( postData)
    webclient.UploadStringAsync(Uri(base_url, UriKind.Absolute), "POST", postData)
    
def GetStationPlayList(artist):
    method = "radio.getPlaylist"
    url = "?api_key=" + api_key + "&" + "method=" + method + "&" + "sk=" + session_key + "&" + "station=/listen/artist/"+artist+"&" + "api_sig=";
    presig = "api_key" + api_key + "method" + method + "sk" + session_key + "station/listen/artist/"+ artist + secret;
    api_sig = HtmlPage.Window.Invoke("GetMD5", presig)
    url += api_sig;
    webclient = WebClient()
    webclient.DownloadStringCompleted += webclient_DownloadStringCompleted
    webclient.DownloadStringAsync(Uri(base_url + url, UriKind.Absolute))

artist = "genesis"
TuneIn(artist)
GetStationPlayList(artist)